今天來看看Gin的Middleware,Middleware是一種中介軟體,可以在處理請求前後做一些事情,例如驗證、日誌、錯誤處理等等。本質上跟你的API handler function 一樣是一個gin.HandlerFunc
你可以設定Global Middleware,或只對特定的路由設定Middleware。
假設我們現在有一個Middleware叫Logger,用來記錄請求的時間與路徑等request資訊,那麼我們可以透過以下方式設定Middleware
透過func (engine *gin.Engine) Use(middleware ...gin.HandlerFunc) gin.IRoutes
進行設置
r.Use(Logger())
如果我們想要針對特定的Route進行Middleware,針對Route或Group進行Middleware的設定方式會有所不同
假設我們要針對/cors
設定允許CORS的Middleware, 那麼我們可以這樣設定
func CORSMiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
c.Next()
}
}
r.Group
可以用來建立一個Group,它可以把相同prefix的Route放在一起,Group.Use
進行設定sequence := r.Group("/sequence")
sequence.Use(Counter())
{
sequence.GET("/first", func(c *gin.Context) {
c.String(200, "first")
})
sequence.GET("/second", func(c *gin.Context) {
c.String(200, "second")
})
}
設定完後sequence
這個Group中的所有Route都會套用Counter
這個Middleware
c.Next()
這個函數用來執行下一個Middleware或是handler function,你可以理解成你的Handler function被分成上下兩部分(以c.Next()
為分界),上半部分用來初始化,下半部分用來做request後的處理
對於c.Next
, 如果有多個Middleware的話c.Next()
會依序執行下一個Middleware或是handler function,直到最後一個Middleware或是handler function完成後,再回到上一個Middleware繼續執行。
可以理解成當你呼叫c.Next()
時,把目前的handler function放到一個stack中,然後執行下一個Middleware或是handler function,當下一個Middleware或是handler function執行完後,再從stack中取出上一個handler function繼續執行後續部份
func Handler1(c *gin.Context) {
fmt.Println("Handler1: before next")
c.Next()
fmt.Println("Handler1: after next")
}
func Handler2(c *gin.Context) {
fmt.Println("Handler2: before next")
c.Next()
fmt.Println("Handler2: after next")
}
r.GET("/next", Handler1, Handler2, func(c *gin.Context) {
fmt.Println("Handler3")
c.JSON(200, gin.H{"message": "next"})
})
// response
/*
Handler1: before next
Handler2: before next
Handler3
Handler2: after next
Handler1: after next
*/
c.Abort()
有時候,處理的結果可能不會是你想要的,又或者某些部份出了問題。這時候你可以透過c.Abort()
來停止執行後續的Middleware或是handler function,並且直接回傳結果。然後執行上一個Middleware或是handler function的Next
下面的部份。可以理解成透過c.Abort()
來將這個handler function作為最後一個handler function執行。
要留意的是,Abort() 要寫在 Next() 之前才有效果,
func cond() bool {
return true
}
func Handler1(c *gin.Context) {
fmt.Println("Handler1: before next")
c.Next()
fmt.Println("Handler1: after next")
}
func Handler2(c *gin.Context) {
fmt.Println("Handler2: before next")
if flag := cond(); flag {
c.Abort()
}
c.Next()
fmt.Println("Handler2: after next")
}
r.GET("/abort", Handler1, Handler2, func(c *gin.Context) {
fmt.Println("Handler3")
c.JSON(200, gin.H{"message": "abort"})
})
// response
/*
Handler1: before next
Handler2: before next
Handler2: after next
Handler1: after next
*/
c.Abort
有3個變體,分別是c.Abort()
, c.AbortWithStatus(code int)
, c.AbortWithStatusJSON(code int, jsonObj interface{})
c.Abort()
: 終止後續的Middleware或是handler function,並且直接回傳結果c.AbortWithStatus(code int)
: 終止後續的Middleware或是handler function,並且直接回傳指定的HTTP Status Codec.AbortWithStatusJSON(code int, jsonObj interface{})
: 終止後續的Middleware或是handler function,並且直接回傳指定的HTTP Status Code與JSON Responsec.AbortWithError(code int, err error)
: 終止後續的Middleware或是handler function,並且直接回傳指定的HTTP Status Code與錯誤訊息那麼今天的文章就到這告一段落,如果我的文章有任何地方有錯誤請在留言區反應
明天將會講如何在Gin中架設RESTful API